﻿/* 【MicroDBHelper】，用于封装与数据库操作相关的方法。
 * 该类完全依赖SQLHELPER
 * 
 *  这个封装类的主要的目标：
 *  1.希望封装重复、重要的操作步骤，降低编码疏忽而引起的DB问题；
 *  2.而非功能方面的灵活或全面，因此功能上会少于下层的Helper。
 *  
 * 
 *  使用说明：
 *  1.提供3个基础的DB操作接口,其中“参数1”为SQL语句，“参数2”为参数数据，“参数3”为是否使用事务(传null时，表示不使用事务，新建连接去处理)
      MicroDBHelper.ExecuteNonQuery(sql, paramValues, tran);
      MicroDBHelper.ExecuteDataTable(sql, paramValues, tran);
      MicroDBHelper.ExecuteScalar(sql, paramValues, tran); 
 *    
 *  2.使用事务时，请用using包括，
      using (var tran = MicroDBHelper.UseTransaction(隔离等级)) 
      {
         MicroDBHelper.ExecuteNonQuery(sql, paramValues, tran);
         tran.MarkSuccess();
      }
 *    成功执行的最后，请调用MarkSuccess()，事务结束前会自动Commit；发生错误或者不显式MarkSuccess()的情况下，均会自动Rollback所有修改;
 *     
 *  3.隔离级别，根据实际情况进行选择。选择依据：
      未提交读（read uncommitted）   当事务A更新某条数据时，不容许其他事务来更新该数据，但可以读取。
      提交读（read committed） 	    当事务A更新某条数据时，不容许其他事务进行任何操作包括读取，但事务A读取时，其他事务可以进行读取、更新
      重复读（repeatable read） 	    当事务A更新数据时，不容许其他事务进行任何操作，但当事务A进行读取时，其他事务只能读取，不能更新。
      序列化（serializable）         最严格的隔离级别，事务必须依次进行。
 *    
 */

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Text;
using AsyncSQLHelper = Microsoft.SqlHelper;
using SyncSQLHelper  = Microsoft.SqlHelper;

namespace LabelPrintSystem
{
    public sealed class MicroDBHelper
    {//依赖官方 MS-SQLHelper;
        public const string ALIAS_NAME_DEFAULT = "DEFAULT";
        //const string ERRMSG_TRANSACTION_IS_NULL = "指定的事务为空！";
        const string ERRMSG_TRANSACTION_IS_NULL = "The Specified Transaction is null!";

        //----------Members-----------

        #region 连接字符串

        private static Dictionary<string,string> connectionStrings = new Dictionary<string,string>();

        public static void SetConnection(string m_connectionString,string m_ConnectionAliasName = ALIAS_NAME_DEFAULT)
        {
            //检查连接字符串
            SqlConnectionStringBuilder builder = null;
            try
            {
                builder = new SqlConnectionStringBuilder(m_connectionString);
            }
            catch (Exception ex)
            {
                //const string errMsg = "连接字符串有错误。";
                const string errMsg = "Connection String is invalid。";

                throw new ArgumentException(errMsg, "m_connectionString", ex);
            }

            //现在无法使用
            //##异步的(需支持点NET版本V4.5+)
            /* 启用异步SQL支持的时候，连接字符串必须包含以下属性。
             * https://msdn.microsoft.com/zh-cn/library/system.data.sqlclient.sqlconnectionstringbuilder.asynchronousprocessing(v=vs.110).aspx
             * 
             * 标记为“允许异步”。即：
             * 1.没有标记时，及时使用Command的Async方法，依然是同步操作；
             * 2.有标记时，如果继续使用Command的同步方法，仍然能用于同步操作。
             */
            builder.AsynchronousProcessing              = true;
            connectionStrings[m_ConnectionAliasName]    = builder.ToString();
        }

        internal static string GetConnection(string m_ConnectionAliasName = ALIAS_NAME_DEFAULT)
        {
            string result = null;
            if (connectionStrings.TryGetValue(m_ConnectionAliasName, out result))
                return result;
            else
            {
                //const string errMsg1 = "预期的链接字符串不存在。";
                //const string errMsg2 = "连接别名不存在:";
                const string errMsg1 = "the target Connection String is not exist。";
                const string errMsg2 = "the Specified Alias Name was not setted.";  

                throw new InvalidOperationException(errMsg1, new System.ArgumentOutOfRangeException("m_ConnectionAliasName", errMsg2 + m_ConnectionAliasName));
            }
        }

        #endregion

        private MicroDBHelper()
        {}
		
        public static DataTable ExecuteDataTable(string commandText, SqlParameter[] commandParameters, 
                                                 MicroDBTransaction transaction, CommandType commandType = CommandType.Text)
        {//查询，返回表
            DataSet ds =  SyncSQLHelper.ExecuteDataset(transaction.tran, commandType, commandText, commandParameters);
            
            //返回结果
            if (ds == null || ds.Tables == null || ds.Tables.Count <= 0)
                return null;
            return ds.Tables[0];
        }

        public static DataTable ExecuteDataTable(string commandText, SqlParameter[] commandParameters, 
                                                 string connectionAliasName = ALIAS_NAME_DEFAULT, CommandType commandType = CommandType.Text)
        {
            DataSet ds = SyncSQLHelper.ExecuteDataset(GetConnection(connectionAliasName), commandType, commandText, commandParameters);
            
            //返回结果
            if (ds == null || ds.Tables == null || ds.Tables.Count <= 0)
                return null;
            return ds.Tables[0];
        }

        public static object ExecuteScalar(string commandText, SqlParameter[] commandParameters, 
                                           MicroDBTransaction transaction, CommandType commandType = CommandType.Text)
        {//查询，返回单一结果
            return SyncSQLHelper.ExecuteScalar(transaction.tran, commandType, commandText, commandParameters);
        }

        public static object ExecuteScalar(string commandText, SqlParameter[] commandParameters, 
                                           string connectionAliasName = ALIAS_NAME_DEFAULT, CommandType commandType = CommandType.Text)
        {
            return SyncSQLHelper.ExecuteScalar(GetConnection(connectionAliasName), commandType, commandText, commandParameters);
        }

        public static int ExecuteNonQuery(string commandText, SqlParameter[] commandParameters, 
                                          MicroDBTransaction transaction, CommandType commandType = CommandType.Text)
        {//执行，返回受影响行数
            if (transaction == null) throw new InvalidOperationException(ERRMSG_TRANSACTION_IS_NULL, new ArgumentNullException("transaction"));

            return SyncSQLHelper.ExecuteNonQuery(transaction.tran, commandType, commandText, commandParameters);
        }

        public static int ExecuteNonQuery(string commandText, SqlParameter[] commandParameters, 
                                          string connectionAliasName = ALIAS_NAME_DEFAULT, CommandType commandType = CommandType.Text)
        {
            return SyncSQLHelper.ExecuteNonQuery(GetConnection(connectionAliasName), commandType, commandText, commandParameters);
        }


        //------Extend Methods----------

        #region 获取事务支持的对象

        public static MicroDBTransaction UseTransaction(IsolationLevel IsolationLevel, string ConnectionAliasName = ALIAS_NAME_DEFAULT)
        {
            MicroDBTransaction result = new MicroDBTransaction(IsolationLevel, ConnectionAliasName);

            bool ready = result.MakeReady();
            if (ready == false)
            {
                //const string errMsg = "数据库连接打开失败!";
                const string errMsg = "DB connection open faild!";
                throw new InvalidOperationException(errMsg);
            }

            return result;
        }

        #endregion

    }
}

